package com.bestcem.xm.user.service.impl.third;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.user.config.properties.OaProperties;
import com.bestcem.xm.user.config.properties.SettingProperties;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.enums.BooleanStatusEnum;
import com.bestcem.xm.user.service.third.OaService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Oa相关服务
 *
 * @author qiongyu.cui <qiongyu.cui@idiaoyan.com>
 * @version v1.0
 * @date 2022/3/2 10:41
 */
@Service
@Slf4j
public class OaServiceImpl implements OaService {
    private static final Logger EMAIL_LOG = LoggerFactory.getLogger("EmailErrorLog");

    @Resource
    private OaProperties oaProperties;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private RedisService redisService;

    @Resource
    private SettingProperties settingProperties;

    private static final String ACCESS_TOKEN_KEY = "access_token";
    private static final Integer ACCESS_TOKEN_EXPIRATION_TIME = 3;

    @Override
    public ServiceResult<String> getToken() {
        // 基线环境直接返回
        if (settingProperties.isBaseLine()) {
            return ServiceResult.success();
        }

        // python引用：apps_mysql.user.oa_helper.OAHelper.get_token
        // auth 接口数据格式非json
        if (StringUtils.isBlank(oaProperties.getUrl())
                || StringUtils.isBlank(oaProperties.getPassword())
                || StringUtils.isBlank(oaProperties.getUsername())) {
            log.info("[User] 请求用户oa服务获取token失败，相关配置信息缺失！");
            return ServiceResult.fail("相关配置信息缺失");
        }

        // 先读取缓存
        Object token = redisService.get(UserCacheKeyConstant.OA_TOKEN_KEY);
        if (Objects.nonNull(token)) {
            return ServiceResult.success(token.toString());
        }

        try {
            HttpHeaders httpHeaders = new HttpHeaders();
            //头部类型
            httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            // 请求第三方获取token信息
            // auth 接口数据格式非json
            MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
            //构造实体对象
            map.add("username", oaProperties.getUsername());
            map.add("password", oaProperties.getPassword());

            HttpEntity<MultiValueMap<String, Object>> param = new HttpEntity<>(map, httpHeaders);
            ResponseEntity<String> apiResponse = restTemplate.postForEntity(oaProperties.getAuthUrl(), param, String.class);

            // 解析返回内容
            JSONObject response = JSON.parseObject(apiResponse.getBody());
            if (null == response || !response.containsKey(ACCESS_TOKEN_KEY)) {
                log.info("[User] 请求用户oa服务未获得token信息");
                // 发送异常邮件给指定的oa配置
                sendExceptionEmail("USER:OA:" + oaProperties.getAuthUrl(), "请求用户oa服务未获得token信息");
                return ServiceResult.fail("未获得token信息");
            }
            token = (String) response.get(ACCESS_TOKEN_KEY);
            redisService.set(UserCacheKeyConstant.OA_TOKEN_KEY, token, ACCESS_TOKEN_EXPIRATION_TIME, TimeUnit.DAYS);
            return ServiceResult.success(token.toString());
        } catch (Exception e) {
            log.error("[User] 调用oa服务获取token失败", e);
            // 发送异常邮件给指定的oa配置
            sendExceptionEmail("USER:OA:" + oaProperties.getAuthUrl(), e.getMessage());
            return ServiceResult.fail("调用oa服务获取token失败！");
        }
    }

    @Override
    public ServiceResult<Boolean> checkMobile(String mobile) {
        // 基线环境直接返回
        if (settingProperties.isBaseLine()) {
            return ServiceResult.success(false);
        }

        // 获取配置文件中的OA_URL
        if (StringUtils.isEmpty(oaProperties.getUrl())) {
            log.error("[User] 调用oa服务检查手机号码是否是内部员工失败：服务地址不能为空");
            return ServiceResult.success(false);
        }

        // 获取oa的token信息
        ServiceResult<String> tokenResult = getToken();
        if (!tokenResult.isSuccess()) {
            return ServiceResult.success(false);
        }

        String token = tokenResult.getData();
        try {
            // 请求第三方检查手机号是否为内部用户
            HttpHeaders httpHeaders = new HttpHeaders();
            MediaType type = MediaType.parseMediaType("application/x-www-form-urlencoded");
            httpHeaders.setContentType(type);
            httpHeaders.add("Authorization", "Bearer " + token);
            Map<String, String> param = new HashMap<>();
            param.put("mobile", mobile);
            String body = JSON.toJSONString(param);
            HttpEntity<String> httpEntity = new HttpEntity<>(body, httpHeaders);
            ResponseEntity<String> apiResponse = restTemplate.postForEntity(oaProperties.getCheckUrl(), httpEntity, String.class);

            // 解析返回内容
            JSONObject response = JSON.parseObject(apiResponse.getBody());
            Object result = response.get("result");
            log.info("[USER]OA服务手机校验，result={}", result);
            return ServiceResult.success(Objects.nonNull(result) && BooleanStatusEnum.toBoolean((int) result));
        } catch (Exception e) {
            log.error("[User] 调用oa服务检查手机号是否为内部用户失败", e);
            // 发送异常邮件给指定的oa配置
            sendExceptionEmail("USER:OA:" + oaProperties.getAuthUrl(), e.getMessage());
            return ServiceResult.fail("调用oa服务检查手机号是否为内部用户失败！");
        }
    }

    /**
     * 请求异常，发送异常邮件告知指定的oa管理员
     *
     * @param detail 错误描述
     * @param errMsg 异常内容
     * @author cuiqiongyu <qiongyu.cui@idiaoyan.cn>
     * @date 2022/03/02 14:16
     */
    private void sendExceptionEmail(String detail, String errMsg) {
        log.error("[USER] 异常信息:{} ErrorMsg: {}", detail, errMsg);
        EMAIL_LOG.error("[USER] ErrorMsg: {} ErrorMsg: {}", detail, errMsg);
    }

}
